/* wpa_ctrl.c */
#include "wpacli.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <errno.h>

static void set_nonblock(int sock) {
    int flags = fcntl(sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

static void *event_loop(void *arg) {
    wpa_conn *conn = arg;
    char buffer[4096];

    while (1) {
        ssize_t n = recv(conn->sockfd, buffer, sizeof(buffer)-1, 0);
        if (n <= 0) {
            if (conn->non_block && errno == EAGAIN) {
                usleep(100000); // 100ms
                continue;
            }
            break;
        }

        buffer[n] = '\0';
        if (conn->event_callback)
            conn->event_callback(buffer);
    }
    return NULL;
}
static int create_client_socket(struct sockaddr_un *local) {
    int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
    if (sock < 0) return -1;

    // 创建控制目录
    mkdir(CTRL_CLIENT_DIR, 0777);

    memset(local, 0, sizeof(*local));
    local->sun_family = AF_UNIX;

    int counter = 0;
    while (counter < 10) {
        snprintf(local->sun_path, sizeof(local->sun_path),
                "%s/%s%d-%d", CTRL_CLIENT_DIR, 
                CTRL_CLIENT_PREFIX, getpid(), counter++);

        if (bind(sock, (struct sockaddr *)local, sizeof(*local)) == 0) {
            chmod(local->sun_path, 0666);
            return sock;
        }

        if (errno == EADDRINUSE) {
            unlink(local->sun_path);
            continue;
        }
        break;
    }
    close(sock);
    return -1;
}

wpa_conn *wpa_connect(const char *ctrl_path, bool non_block, int *err) {
    wpa_conn *conn = calloc(1, sizeof(wpa_conn));
    struct sockaddr_un local;

    // 创建并绑定客户端套接字
    if ((conn->sockfd = create_client_socket(&local)) < 0) {
        *err = WPA_BIND_ERROR;
        goto error;
    }
    strcpy(conn->client_path, local.sun_path);

    // 配置目标地址
    memset(&conn->dest, 0, sizeof(conn->dest));
    conn->dest.sun_family = AF_UNIX;
    strncpy(conn->dest.sun_path, ctrl_path, sizeof(conn->dest.sun_path)-1);

    // 连接服务端
    if (connect(conn->sockfd, (struct sockaddr *)&conn->dest, sizeof(conn->dest)) < 0) {
        *err = WPA_CONNECT_ERROR;
        goto error;
    }

    // 设置非阻塞模式
    if (non_block) {
        set_nonblock(conn->sockfd);
        conn->non_block = true;
    }

    // 启动事件线程
    if (pthread_create(&conn->event_thread, NULL, event_loop, conn)) {
        *err = WPA_SOCKET_ERROR;
        goto error;
    }

    *err = WPA_OK;
    return conn;

error:
    wpa_disconnect(conn);
    return NULL;
}

int wpa_send_command(wpa_conn *conn, const char *cmd, char *reply, size_t *reply_len) {
    ssize_t res = send(conn->sockfd, cmd, strlen(cmd), 0);
    if (res < 0) return WPA_SEND_ERROR;

    // 同步等待响应
    if (reply) {
        struct timeval tv = {CTRL_TIMEOUT, 0};
        fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(conn->sockfd, &rfds);

        if (select(conn->sockfd+1, &rfds, NULL, NULL, &tv) <= 0)
            return WPA_RECV_ERROR;

        res = recv(conn->sockfd, reply, *reply_len, 0);
        if (res <= 0) return WPA_RECV_ERROR;
        reply[res] = '\0';
    }
    return WPA_OK;
}


void wpa_disconnect(wpa_conn *conn) {
    if (!conn) return;

    shutdown(conn->sockfd, SHUT_RDWR);
    close(conn->sockfd);
    unlink(conn->client_path);
    pthread_cancel(conn->event_thread);
    free(conn);
}

const char *wpa_strerror(int errcode) {
    static const char *errors[] = {
        "Success",
        "Socket creation failed",
        "Bind failed",
        "Connect failed",
        "Send command failed",
        "Receive failed"
    };
    return (errcode >=0 && errcode <=5) ? errors[errcode] : "Unknown error";
}